#!/usr/bin/env python
# -*- coding: utf-8 -*-

#-*-
# UbiNote - A Lightweight Note-talking Application
#
# Copyright (C) 2006-2009 Shellex <5h3ll3x@gmail.com>
#
# UbiNote is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# UbiNote is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with UbiNote; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA


from dbmgr import dbmgr
import mimetypes
import json
import urllib
import cgi
import urlparse
import select
import os
import Cookie
import shutil
import SimpleHTTPServer
import cStringIO
import sys
import re

class waiter(SimpleHTTPServer.SimpleHTTPRequestHandler): 
    rpc_paths = ('/RPC2',)
    base_path = '../data/web_content'
    def __init__(s, a, b, c):
        dbmgr.attach('../data/db/ubnote.db.sqlite')
        s.conn = dbmgr.get_conn()
        
        s.respond_str = ''
        s.snd_url = ''
        s.mimetype = 'text/html'    
        s.resp_headers={}
        s.action = ''
        s.vpath = ''
        s.qs = {}
        s.body = {} 
        
        idx = waiter.base_path.rfind('/', 1)
        s.web_mod_path = waiter.base_path[:idx]
        s.web_mod_name = waiter.base_path[idx+1:]
        sys.path.append(s.web_mod_path)

        s.cookie=Cookie.SimpleCookie()
        s.load_site()
        mimetypes.init()
        SimpleHTTPServer.SimpleHTTPRequestHandler.__init__(s, a, b,c)

       
    def get_mimetype(s, file):
        type, encoding = mimetypes.guess_type(file)
        return type

    def respond(s, str):
        s.respond_str += str

    def format_url(s):
        """get action and query-string from s.path"""
        path_tail = s.path if s.path.find('/', 1) == -1 else s.path[:s.path.find('/',1)]
        if path_tail.find('?', 1) != -1:
            s.action, s.qs = path_tail.split('?')
            s.qs = urllib.unquote_plus(s.qs)
            s.qs = urlparse.parse_qs(s.qs)
            s.qs = dict([[k,c[0]] for k,c in s.qs.iteritems()])
        else:
            s.action, s.qs = path_tail, {}



    def make_header(s):
        s.sys_version = 'Unix'
        s.server_version = 'WFS/0.1(mod cgi)'
        s.resp_headers["Server"] = "Unix WFS/0.1(mod cgi)"
        s.resp_headers = {"Content-type":'text/html'} # default

    def do_GET(s):
        """Begin serving a GET request"""
        s.make_header()
        s.format_url()
        s.handle_data()
        

    def do_POST(s):
        """Begin serving a POST request. The request data is readable
        on a file-like object called s.rfile"""
        s.make_header()
        ctype, pdict = cgi.parse_header(s.headers.getheader('content-type'))
        length = int(s.headers.getheader('content-length'))
        if ctype == 'multipart/form-data':
            s.body = cgi.parse_multipart(s.rfile, pdict)
        elif ctype == 'application/x-www-form-urlencoded':
            qs = s.rfile.read(length)
            # cgi.parse_qs was deprecated in py3k
            # assign to query string ... it's more convenient
            s.qs = urlparse.parse_qs(qs, keep_blank_values=1)
            s.qs = dict([[k,c[0]] for k,c in s.qs.iteritems()])
        else:
            s.body = {}                   # Unknown content-type
        # some browsers send 2 more bytes...
        [ready_to_read,x,y] = select.select([s.connection],[],[],0)
        if ready_to_read:
            s.rfile.read(2)
        
        s.handle_data()

    def handle_data(s):
        s.vpath = s.path
        if s.vpath.find('?') > 1: #remove query string
            s.vpath = s.vpath.split('?', 1)[0]

        if s.vpath == '/':
            s.vpath = s.vpath + 'ui.html'
        # and translate...
        s.vpath = s.base_path + s.vpath

        if os.path.isdir(s.vpath):
            # list directory
            dir_list = s.list_directory(s.vpath)
            s.copyfile(dir_list, s.wfile)
            return
        # s.translate_path(path)
        ext = os.path.splitext(s.vpath)[1].lower()

        if len(ext) > 1 and hasattr(s, "run_%s" % ext[1:]):
            exec ('s.run_%s()' % ext[1:])
        else:
            ctype = s.get_mimetype(s.vpath)
            if ctype.startswith('text/'):
                mode = 'r'
            else:
                mode = 'rb'
            try:
                f = open (s.vpath, mode)
                s.resp_headers['Content-type']=ctype
                s.resp_headers['Content-length']=str(os.fstat(f.fileno())[6])
                s.done(200, f)
            except IOError:
                s.send_error(404, "File not found")

    def run_do (s):
        """
        """
        def qs2params(qs_p):
            params = []
            print qs_p,  s.qs
            # remove empty string
            for name in filter(lambda x: len(x)!=0, [e.strip() for e in qs_p.split(',')]):
                if s.qs.has_key(name):
                    params.append(s.qs[name])
                else:
                    return None
            return tuple(params)

        path = s.path.split('?')[0]
        if path[0] == '/':
            path = path[1:]
        for (path_p, qs_p, proc_path) in s.mapping:
            if path_p == path:
                params = qs2params(qs_p)
                if params != None:
                    s.run_function(proc_path, params)
                    break
        # refacting...
        #if not flag:
        #    solve = response_strategy.response_solve.get_inst()
        #    result = solve.process(s.action[1:], s.qs)
        #    s.respond(json.dumps(result))
        #    s.done(200)

            
    def load_site(s):
        if os.path.exists(s.base_path + '/__init__.py'):
            exec ('from %s import mapping' % s.web_mod_name)
        s.mapping = mapping

    def run_function(s, proc_path, params):
        idx = proc_path.rfind('.')
        mod = proc_path[:idx]
        func = proc_path[idx+1:]
        print mod, func
        try:
            exec ('from %s.%s import %s' % (s.web_mod_name, mod, func))
        except ImportError, e:
            print 'Error Import'
        print 'apply...'
        exec ('apply(%s, (s, ) + params)' % func)

    def run_py (s):
        """Run a Python script file"""
        script = s.translate_path(s.vpath)
        # redirect stdout 
        sys.stdout = cStringIO.StringIO()
        try:
            execfile (script)
        except HTTP_REDIRECTION,url:
            s.resp_headers['Location'] = url
            s.done(301,cStringIO.StringIO())
        except:
            # print a traceback
            # first reset the output stream
            sys.stdout = cStringIO.StringIO()
            exc_type,exc_value,tb=sys.exc_info()
            msg = exc_value.args[0]
            if tb.tb_next is None:     # errors (detected by the parser)
                line = exc_value.lineno
                text = exc_value.text
            else:                      # exceptions
                line = tb.tb_next.tb_lineno
                text = open(script).readlines()[line-1]
            print '%s in file %s : %s' %(exc_type.__name__,
                os.path.basename(script), cgi.escape(msg))
            print '<br>Line %s' %line
            print '<br><pre><b>%s</b></pre>' %cgi.escape(text)
        s.resp_headers['Content-length'] = sys.stdout.tell()
        s.done(200,sys.stdout)


    def done(s, code, infile=None):
        """Send response, cookies, response headers 
        and the data read from infile"""
        s.send_response(code)
        for morsel in s.cookie.values():
            s.send_header('Set-Cookie', morsel.output(header='').lstrip())
        for (k,v) in s.resp_headers.items():
            s.send_header(k,v)
        s.end_headers()
        if (infile != None):
            infile.seek(0)
            #shutil.copyfileobj(infile, s.wfile)
            s.copyfile(infile, s.wfile)
        else:
            s.wfile.write(s.respond_str)

if __name__ == "__main__":
    import SocketServer
    port = 8000
    server = SocketServer.TCPServer(('', 8000), waiter)
    try:
        server.serve_forever()
    except KeyboardInterrupt:
        server.socket.close()
    except :
        server.socket.close()
    server.socket.close()
    print 'Server Stop'

